#include "Dx11Demo.h"



Dx11Demo::Dx11Demo(void) : m_effect(0),m_vertexShader(0), m_pixelShader(0), 
  m_inputLayout(0), m_vertexBuffer(0)
{
  
}


Dx11Demo::~Dx11Demo(void)
{
}


bool Dx11Demo::LoadContent()
{
  ID3DBlob* buffer = 0;
  bool compileResult = this->CompileD3DShader("Shaders/SolidGreen.fx", 0, "fx_5_0", &buffer);

  if(!compileResult)
  {
    MessageBox(0, "Error compiling effect!", "Error", MB_OK);
    return false;
  }

  HRESULT d3dResult;

  d3dResult = D3DX11CreateEffectFromMemory(buffer->GetBufferPointer(), buffer->GetBufferSize(), 0, this->m_d3dDevice, &this->m_effect);

  if(FAILED(d3dResult))
  {
    MessageBox(0, "Error creating effect shader!", "Error", MB_OK);
    if(buffer)
      buffer->Release();
    return false;
  }

  D3D11_INPUT_ELEMENT_DESC layouts[] = 
  {
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
  };


  unsigned int totalLayoutElements = ARRAYSIZE(layouts);

  ID3DX11EffectTechnique* technique = this->m_effect->GetTechniqueByName("Alpha");
  ID3DX11EffectPass* pass = technique->GetPassByIndex(0);

  D3DX11_PASS_SHADER_DESC passDesc;
  D3DX11_EFFECT_SHADER_DESC effectDesc;
  pass->GetVertexShaderDesc(&passDesc);
  passDesc.pShaderVariable->GetShaderDesc( passDesc.ShaderIndex, &effectDesc );


  d3dResult = this->m_d3dDevice->CreateInputLayout(layouts, totalLayoutElements, effectDesc.pBytecode, 
    effectDesc.BytecodeLength, &this->m_inputLayout);

  buffer->Release();

  if(FAILED(d3dResult))
  {
    return false;
  }
  

  ObjModel model;
  if(model.LoadObj("Models/sphere.obj") == false)
  {
    DXTRACE_MSG("Error loading 3D model!");
    return false;
  }


  this->m_totalVerts = model.GetTotalVerts();
  VertexPos* vertices = new VertexPos[this->m_totalVerts];

  float* vertsPtr = model.GetVertices();
  float* texCCPtr = model.GetTexCoors();

  for(int i = 0; i < this->m_totalVerts; ++i)
  {
    vertices[i].pos = XMFLOAT3(*(vertsPtr+0), *(vertsPtr+1), *(vertsPtr+2));
    vertsPtr+=3;
    if(texCCPtr)
    {
      vertices[i].tex0 = XMFLOAT2(*(texCCPtr+0), *(texCCPtr+1));
      texCCPtr+=2;
    }
  }
  /*
  VertexPos vertices[] =
  {
    { XMFLOAT3( -1.0f,  1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3(  1.0f,  1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3(  1.0f,  1.0f,  1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f,  1.0f,  1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3(  1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3(  1.0f, -1.0f,  1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, -1.0f,  1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f,  1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( -1.0f,  1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f,  1.0f,  1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3(  1.0f, -1.0f,  1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3(  1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3(  1.0f,  1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3(  1.0f,  1.0f,  1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3(  1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3(  1.0f,  1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f,  1.0f, -1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f,  1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3(  1.0f, -1.0f,  1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3(  1.0f,  1.0f,  1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f,  1.0f,  1.0f ), XMFLOAT2( 0.0f, 1.0f ) },
  };
  */

  D3D11_BUFFER_DESC vertexDesc;
  ZeroMemory(&vertexDesc, sizeof(vertexDesc));
  vertexDesc.Usage = D3D11_USAGE_DEFAULT;
  vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
  vertexDesc.ByteWidth = sizeof(VertexPos) * this->m_totalVerts;

  D3D11_SUBRESOURCE_DATA resourceData;
  ZeroMemory(&resourceData, sizeof(resourceData));
  resourceData.pSysMem = vertices;

  d3dResult = this->m_d3dDevice->CreateBuffer(&vertexDesc, &resourceData, &this->m_vertexBuffer);

  if(FAILED(d3dResult))
  {
    return false;
  }

  //delete[] vertices;
  d3dResult = D3DX11CreateShaderResourceViewFromFile(this->m_d3dDevice, "Textures/wood1.jpg",0,0,&this->m_colorMap,0);

  if(FAILED(d3dResult))
  {
    DXTRACE_MSG("Failed to load the texture image!");
    return false;
  }

  /*
  WORD indices[] =
  {
    3,   1,  0,  2,  1,  3,
    6,   4,  5,  7,  4,  6,
    11,  9,  8, 10,  9, 11,
    14, 12, 13, 15, 12, 14,
    19, 17, 16, 18, 17, 19,
    22, 20, 21, 23, 20, 22
  };

  D3D11_BUFFER_DESC indexDesc;
  ZeroMemory( &indexDesc, sizeof( indexDesc ) );
  indexDesc.Usage = D3D11_USAGE_DEFAULT;
  indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
  indexDesc.ByteWidth = sizeof( WORD ) * 36;
  indexDesc.CPUAccessFlags = 0;
  resourceData.pSysMem = indices;

  d3dResult = this->m_d3dDevice->CreateBuffer( &indexDesc, &resourceData, &this->m_indexBuffer );

  if( FAILED( d3dResult ) )
  {
    DXTRACE_MSG( "Failed to create index buffer!" );
    return false;
  }
  */

  D3D11_SAMPLER_DESC colorMapDesc;
  ZeroMemory(&colorMapDesc, sizeof(colorMapDesc));

  colorMapDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
  colorMapDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
  colorMapDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
  colorMapDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
  colorMapDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
  colorMapDesc.MaxLOD = D3D11_FLOAT32_MAX;



  d3dResult = this->m_d3dDevice->CreateSamplerState(&colorMapDesc, &this->m_colorMapSampler);

  if(FAILED(d3dResult))
  {
    DXTRACE_MSG("Failed to create color map sampler state!");
    return false;
  }

  XMMATRIX projMat = XMMatrixPerspectiveFovLH(XM_PIDIV4, 800.0f / 600.0f, 0.01f, 100.0f);
  

  XMStoreFloat4x4(&this->m_projMatrix, projMat);
  

  this->m_camera.SetPosition(XMFLOAT3(3,3,-12), XMFLOAT3(0,0,0));
  //m_camera.SetDistance(-10,-50,50);
  
  XMStoreFloat4x4(&this->m_viewMatrix, this->m_camera.GetViewMatrix());

  return true;
}

void Dx11Demo::UnloadContent()
{
  if(this->m_colorMapSampler) this->m_colorMapSampler->Release();
  if(this->m_colorMap) this->m_colorMap->Release();
  if(this->m_vertexShader) this->m_vertexShader->Release();
  if(this->m_pixelShader) this->m_pixelShader->Release();
  if(this->m_inputLayout) this->m_inputLayout->Release();
  if(this->m_vertexBuffer) this->m_vertexBuffer->Release();
  //if(this->m_indexBuffer) this->m_indexBuffer->Release();
  //if(this->m_viewBuffer) this->m_viewBuffer->Release();
  //if(this->m_projBuffer) this->m_projBuffer->Release();
  //if(this->m_worldBuffer) this->m_worldBuffer->Release();

  this->m_colorMapSampler = 0;
  this->m_colorMap = 0;
  this->m_vertexShader = 0;
  this->m_worldBuffer = 0;
  this->m_viewBuffer = 0;
  this->m_projBuffer = 0;
  this->m_pixelShader = 0;
  this->m_inputLayout = 0;
  this->m_vertexBuffer = 0;
}

void Dx11Demo::Update(float dt)
{
  XMMATRIX proj = XMLoadFloat4x4(&m_projMatrix);
  XMMATRIX rot = XMMatrixRotationRollPitchYaw(0,0,dt);

  proj = rot * proj;
  XMStoreFloat4x4(&m_projMatrix, proj);
}

void Dx11Demo::Render()
{
  if(m_d3dContext == 0)
    return;

  float clearColor[4] = {0.0f, 0.0f, 0.25f, 1.0f};
  this->m_d3dContext->ClearRenderTargetView(m_backBufferTarget, clearColor);
  this->m_d3dContext->ClearDepthStencilView(this->m_depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0 );

  unsigned int stride = sizeof(VertexPos);
  unsigned int offset = 0;

  this->m_d3dContext->IASetInputLayout(this->m_inputLayout);
  this->m_d3dContext->IASetVertexBuffers(0, 1, &this->m_vertexBuffer, &stride, &offset);
  this->m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  //this->m_d3dContext->IASetIndexBuffer( this->m_indexBuffer, DXGI_FORMAT_R16_UINT, 0 );

  XMMATRIX rotationMat = XMMatrixRotationRollPitchYaw( 0.0f, 0.0f, 0.0f );
  XMMATRIX translationMat = XMMatrixTranslation( 0.0f, 0.0f, 6.0f );
  XMMATRIX worldMat = rotationMat * translationMat;

  XMMATRIX viewMat = XMLoadFloat4x4(&this->m_viewMatrix);
  XMMATRIX projMat = XMLoadFloat4x4(&this->m_projMatrix);


  ID3DX11EffectShaderResourceVariable* colorMap;
  colorMap = this->m_effect->GetVariableByName( "colorMap" )->AsShaderResource( );
  colorMap->SetResource( this->m_colorMap );

  ID3DX11EffectSamplerVariable* colorMapSampler;
  colorMapSampler = this->m_effect->GetVariableByName( "colorSampler" )->AsSampler( );
  colorMapSampler->SetSampler( 0, this->m_colorMapSampler );

  ID3DX11EffectMatrixVariable* worldMatrix;
  worldMatrix = this->m_effect->GetVariableByName( "worldMatrix" )->AsMatrix( );
  worldMatrix->SetMatrix( ( float* )&worldMat );

  ID3DX11EffectMatrixVariable* viewMatrix;
  viewMatrix = this->m_effect->GetVariableByName( "viewMatrix" )->AsMatrix( );
  viewMatrix->SetMatrix( ( float* )&viewMat );

  ID3DX11EffectMatrixVariable* projMatrix;
  projMatrix = this->m_effect->GetVariableByName( "projMatrix" )->AsMatrix( );
  projMatrix->SetMatrix( ( float* )&projMat );

  ID3DX11EffectTechnique* multiTexTechnique;
  multiTexTechnique = this->m_effect->GetTechniqueByName( "Alpha" );

  D3DX11_TECHNIQUE_DESC techDesc;
  multiTexTechnique->GetDesc( &techDesc );

  for( unsigned int p = 0; p < techDesc.Passes; p++ )
  {
    ID3DX11EffectPass* pass = multiTexTechnique->GetPassByIndex( p );

    if( pass != 0 )
    {
      pass->Apply( 0, this->m_d3dContext );
      this->m_d3dContext->Draw(this->m_totalVerts,0);
      //this->m_d3dContext->DrawIndexed(36,0,0);
    }
  }
  
  m_swapChain->Present(0,0);
}